package com.deng.test.handler;

import com.deng.test.annotation.ResultSkipPack;
import com.deng.test.entity.ResultCode;
import com.deng.test.entity.ResultVo;
import com.deng.test.exception.CustomException;
import com.deng.test.exception.InvalidTokenException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.security.SecurityException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.net.BindException;

@Order(Ordered.HIGHEST_PRECEDENCE)
@RestControllerAdvice(basePackages = "com.deng")
public class ControllerResponseHandler implements ResponseBodyAdvice<Object> {

    private static final Logger logger = LoggerFactory.getLogger(ControllerResponseHandler.class);

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return !(returnType.getParameterType().isAssignableFrom(ResultVo.class) || returnType.hasMethodAnnotation(ResultSkipPack.class));
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        //需要对String类型的值做额外的处理
        if (returnType.getParameterType().equals(String.class)) {
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                return objectMapper.writeValueAsString(new ResultVo<>(body));
            } catch (Exception e) {
                logger.warn("包装返回值失败", e);
                return new ResultVo<>(ResultCode.RESPONSE_PACK_ERROR);
            }
        }
        return new ResultVo<>(body);
    }

    @Order(Ordered.HIGHEST_PRECEDENCE)
    @ExceptionHandler({BindException.class})
    public ResultVo<String> methodArgumentNotValidExceptionHandler(BindException e) {
        //从异常对象中拿到ObjectError对象
        String localizedMessage = e.getLocalizedMessage();
        return new ResultVo<>(ResultCode.REQUEST_PARAM_ERROR, localizedMessage);
    }


    @Order(Ordered.HIGHEST_PRECEDENCE)
    @ExceptionHandler({InvalidTokenException.class})
    public ResultVo<String> methodArgumentNotValidExceptionHandler(InvalidTokenException e) {
        //从异常对象中拿到ObjectError对象
        String localizedMessage = e.getLocalizedMessage();
        return new ResultVo<>(ResultCode.UNAUTH, localizedMessage);
    }
    @Order(Ordered.HIGHEST_PRECEDENCE)
    @ExceptionHandler({CustomException.class})
    public ResultVo<String> cusExceptionHandler(CustomException e) {
        //从异常对象中拿到ObjectError对象
        String localizedMessage = e.getLocalizedMessage();
        return new ResultVo<>(ResultCode.BUSINESS_ERROR, localizedMessage);
    }

    @Order
    @ExceptionHandler({Exception.class})
    public ResultVo<String> otherExceptionHandler(Exception e) {
        e.printStackTrace();
        //从异常对象中拿到ObjectError对象
        String localizedMessage = e.getLocalizedMessage();
        ResultVo<String> stringResultVo = new ResultVo<>(ResultCode.UNKNOW_ERROR, localizedMessage);
        return stringResultVo;
    }

    @Order
    @ExceptionHandler({SecurityException.class})
    public ResultVo<String> SecurityExceptionHandler(SecurityException e) {
        logger.info(e.getLocalizedMessage());
        //从异常对象中拿到ObjectError对象
        String localizedMessage = e.getLocalizedMessage();
        ResultVo<String> stringResultVo = new ResultVo<>(ResultCode.UNAUTH, localizedMessage);
        return stringResultVo;
    }
}
